package com.yangzheandroid.rxmvp.http;

import android.os.Build;
import android.support.annotation.NonNull;

import com.yangzheandroid.retrofitutils.utils.SharePreUtils;
import com.yangzheandroid.rxmvp.APP;
import com.yangzheandroid.rxmvp.api.ApiStore;
import com.yangzheandroid.rxmvp.api.DownloadStore;
import com.yangzheandroid.rxmvp.http.interceptor.BasicParamsInterceptor;
import com.yangzheandroid.rxmvp.http.interceptor.CacheNetInterceptor;
import com.yangzheandroid.rxmvp.http.interceptor.DownloadResponseBodyInterceptor;
import com.yangzheandroid.rxmvp.http.interceptor.LoggerInterceptor;
import com.yangzheandroid.rxmvp.utils.CardUtil;
import com.yangzheandroid.rxmvp.utils.MyUtils;

import java.io.File;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;


public class HttpClients {
    private static final String TAG = HttpClients.class.getSimpleName();
    // 正式环境地址
    public static final String BASE_URL_ONLINE = "https://api.icaibei.net";
    // 测试环境地址
    public static final String BASE_URL_TEST = "https://test.api.icaibei.net";
    // Api Mock 地址
    public static final String BASE_URL_API_MOCK = "http://rap.taobao.org/mockjsdata/6876";

    // 自定义UA
    public static final String ua = "Caibei_v" +
            MyUtils.getVersionName(APP.getInstance()) + "_" +
            MyUtils.getVersionCode(APP.getInstance()) + "/" + MyUtils.getDeviceId(APP.getInstance()) + "/Android_v" +
            Build.VERSION.RELEASE + "/" + Build.MODEL;

    private static final HttpClients INSTANCE = new HttpClients();

    private static final int DEFAULT_TIMEOUT = 10;

    // ----------------------------------------------------------------------------------
    // 定义 Service 单例
    // ----------------------------------------------------------------------------------

    private ApiStore apiStore;
    private DownloadStore downloadService;


    /**
     * 基础api
     */
    public static ApiStore apiStore() {
        return INSTANCE.apiStore;
    }


    /**
     * 下载
     */
    public static DownloadStore downloadService() {
        return INSTANCE.downloadService;
    }

    private HttpClients() {
        // 普通请求
        Interceptor basicParamsInterceptor = new BasicParamsInterceptor();
        CacheNetInterceptor cacheNetInterceptor = new CacheNetInterceptor();
        OkHttpClient okHttpClient = createOkHttpClient(basicParamsInterceptor, null, cacheNetInterceptor);
        Retrofit retrofit = getRetrofit(BASE_URL_ONLINE, okHttpClient);
        apiStore = retrofit.create(ApiStore.class);

        // 文件下载
        Interceptor downloadInterceptor = new DownloadResponseBodyInterceptor();
        OkHttpClient downloadOkHttpClient = createOkHttpClient(null, downloadInterceptor, null);
        Retrofit downloadRetrofit = getRetrofit(BASE_URL_ONLINE, downloadOkHttpClient);
        downloadService = downloadRetrofit.create(DownloadStore.class);
    }

    // ----------------------------------------------------------------------------------
    // 构造器方法
    // ----------------------------------------------------------------------------------

    /**
     * 创建 Retrofit
     */
    private Retrofit getRetrofit(String baseUrl, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
    }

    /**
     * 创建 OkHttpClient
     */
    private OkHttpClient createOkHttpClient(Interceptor interceptor, Interceptor networkInterceptor, CacheNetInterceptor cacheNetInterceptor) {

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .addNetworkInterceptor(new LoggerInterceptor("httplog", true));

//        if (cacheNetInterceptor != null) {
//            builder.addInterceptor(cacheNetInterceptor).addNetworkInterceptor(cacheNetInterceptor);
//        }

        if (interceptor != null) {
            builder.addInterceptor(interceptor);
        }

        if (networkInterceptor != null) {
            builder.addNetworkInterceptor(networkInterceptor);
        }

//        return builder.cache(createOkhttpCache()).build();
        return builder.build();
    }

    @NonNull
    private Cache createOkhttpCache() {
        File httpCacheDirectory = new File(CardUtil.getSDCardPath() + File.separator + "caibei" + File.separator + "httpcache");
        int cacheSize = 20 * 1024 * 1024; // 10 MiB
        return new Cache(httpCacheDirectory, cacheSize);
    }

    // ----------------------------------------------------------------------------------
    // Observable 相关方法
    // ----------------------------------------------------------------------------------

    /**
     * HttpResult 类型转换器
     */
    private static final Func1 httpResultFunction = new Func1() {
        @Override
        public Object call(Object o) {
            HttpResult result = (HttpResult) o;

            if (result.getStatus() >= 900 && result.getStatus() <= 999) {
                //清除缓存
                MyUtils.cleanInternalCache(APP.getInstance(), MyUtils.getCachePath(APP.getInstance(), "httpcache"));
                MyUtils.cleanInternalCache(APP.getInstance(), MyUtils.getCachePath(APP.getInstance(), "image"));

                SharePreUtils.putPreString(APP.getInstance(), "userkey", "");
                SharePreUtils.putPreString(APP.getInstance(), "tokenkey", "");

                throw new ApiException(result.getStatus(), result.getMsg());
            }

            if (result.getStatus() != 0) {

                throw new ApiException(result.getStatus(), result.getMsg());
            }
            return result.getData();
        }
    };

    /**
     * 线程订阅器
     */
    private static final Observable.Transformer defaultTransformer = new Observable.Transformer() {
        @Override
        public Object call(Object observable) {
            return ((Observable) observable)
                    .map(httpResultFunction())
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread());
        }
    };

    /**
     * 用来统一处理Http的错误信息, 并将HttpResult的Data部分剥离出来返回给subscriber
     *
     * @param <T> Subscriber真正需要的数据类型，也就是Data部分的数据类型
     */
    public static <T> Func1<HttpResult<T>, T> httpResultFunction() {
        return httpResultFunction;
    }

    /**
     * 线程订阅器
     */
    public static <T> Observable.Transformer<HttpResult<T>, T> defaultTransformer() {
        return (Observable.Transformer<HttpResult<T>, T>) defaultTransformer;
    }

    /**
     * 发起订阅
     *
     * @param observable 被观察者: http请求
     * @param subscriber 观察者: 处理http请求的业务逻辑
     * @param <T>        类型
     * @return 处理结果
     */
    public static <T> Subscription subscribe(Observable<HttpResult<T>> observable, Subscriber<T> subscriber) {
        return observable
                .compose(HttpClients.<T>defaultTransformer())
                .subscribe(subscriber);
    }

    /**
     * 发起订阅(不需要处理外层结构, 需要获取state)
     *
     * @param observable 被观察者: http请求
     * @param subscriber 观察者: 处理http请求的业务逻辑
     * @param <T>        类型
     * @return 处理结果
     */
    public static <T> Subscription subscribeDefault(Observable<HttpResult<T>> observable, Subscriber subscriber) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}
